/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2022年8月24日
 * V4.0
 */
package com.jphenix.servlet.api.javax;

//#region 【引用区】
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.jphenix.servlet.filter.BaseFilter;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.servlet.api.IHttpSession;
import com.jphenix.standard.servlet.api.IServletContext;
//#endregion

//#region 【说明区】
/**
 * 会话类
 * 
 * 2022-09-04 重构了对接Tomcat9以及以前版本代码
 * 2024-07-14 新增了token模式，即在header中保存token值，通过这个值在内存容器中获取该会话的信息容器
 * 
 * @author MBG
 * 2022年8月24日
 */
//#endregion
@ClassInfo({"2024-07-14 15:59","会话类"})
public class HttpSessionImpl implements IHttpSession {

	//#region 【声明区】
	private HttpSession         kernel     = null; // 核心类实例
	private HttpServletRequest  request    = null; // 请求对象
	private HttpServletResponse response   = null; // 反馈对象
	private BaseFilter          baseFilter = null; // 主过滤器
	//#endregion
	
	//#region 构造函数
	/**
	 * 构造函数
	 * @author MBG
	 */
	public HttpSessionImpl(
			 HttpSession         httpSession
			,HttpServletRequest  req
			,HttpServletResponse resp
			,BaseFilter          bf) {
		super();
		this.kernel     = httpSession;
		this.request    = req;
		this.response   = resp;
		this.baseFilter = bf;
		if(bf!=null && bf.isTokenMode()) {
			// token模式不需要会话超时
			this.kernel.setMaxInactiveInterval(0);
		}
	}
	//#endregion

	//#region getCreationTime()
	/**
	 * 覆盖方法
	 */
	@Override
	public long getCreationTime() {
		return kernel.getCreationTime();
	}
	//#endregion

	//#region getId()
	/**
	 * 覆盖方法
	 */
	@Override
	public String getId() {
		if(baseFilter!=null && baseFilter.isTokenMode()) {
			// token 的 key
			String tokenVal = request.getHeader(baseFilter.getTokenKey());
			if(tokenVal==null || tokenVal.length()<1) {
				tokenVal = response.getHeader(baseFilter.getTokenKey());
				if(tokenVal==null || tokenVal.length()<1) {
					tokenVal = baseFilter.generateTokenId();
					response.setHeader(baseFilter.getTokenKey(),tokenVal);
				}
			}
			return tokenVal;
		}
		return kernel.getId();
	}
	//#endregion

	//#region getLastAccessedTime()
	/**
	 * 覆盖方法
	 */
	@Override
	public long getLastAccessedTime() {
		return kernel.getLastAccessedTime();
	}
	//#endregion

	//#region getServletContext()
	/**
	 * 覆盖方法
	 */
	@Override
	public IServletContext getServletContext() {
		return new ServletContextImpl(kernel.getServletContext());
	}
	//#endregion

	//#region setMaxInactiveInterval(interval)
	/**
	 * 覆盖方法
	 */
	@Override
	public void setMaxInactiveInterval(int interval) {
		if(baseFilter.isTokenMode()) {
			// token 模式不需要设置会话超时信息
			return;
		}
		kernel.setMaxInactiveInterval(interval);
	}
	//#endregion

	//#region getMaxInactiveInterval()
	/**
	 * 覆盖方法
	 */
	@Override
	public int getMaxInactiveInterval() {
		return kernel.getMaxInactiveInterval();
	}
	//#endregion

	//#region getAttribute(name)
	/**
	 * 覆盖方法
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Object getAttribute(String name) {

		//#region 如果整个系统采用token模式
		if(baseFilter!=null && baseFilter.isTokenMode()) {
			
			// token 的 key
			String tokenVal = request.getHeader(baseFilter.getTokenKey());
			if(tokenVal==null || tokenVal.length()<1) {
				tokenVal = response.getHeader(baseFilter.getTokenKey());
				if(tokenVal==null || tokenVal.length()<1) {
					return null;
				}
			}
			
			// 拼装入参对象
			Map<String,Object> paraMap = new HashMap<>();
			paraMap.put("key",tokenVal);        // 设置获取内存值对应的对象（用户数据）
			paraMap.put("type","0");            // 0读取，1写入 2移除
			paraMap.put("time",baseFilter.getSessionTimeOut()); // 设置超时时间

			Map<String,Object> map = null; // 用户会话容器
			try {
				// 调用 内存数据容器 脚本，获取该token对应的用户容器
				map = (Map<String,Object>)baseFilter.getScriptLoader().invokeScript(this,"N100085",paraMap);
			}catch(Exception e) {
				e.printStackTrace();
			}
			if(map==null) {
				//baseFilter.getLog().log("---session getAttribute tokenVal:["+tokenVal+"] key:["+name+"] map is null");
				return null;
			}
			// 获取返回值
			Object res = map.get(name);
			//baseFilter.getLog().log("---session getAttribute tokenVal:["+tokenVal+"] key:["+name+"] mapSize:["+map.size()+"] res:["+res+"]");
			return res;
		}
		//#endregion
		
		return kernel.getAttribute(name);
	}
	//#endregion

	//#region getAttributeNames()
	/**
	 * 覆盖方法
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Enumeration<String> getAttributeNames() {
		// 获取用户的会话容器
		Map<String,Object> map = getAttributeMap();
		if(map!=null) {
			// 获取主键迭代类
			Iterator<String> iterator = map.keySet().iterator();
			
			// 返回枚举类实例
			return new Enumeration() {
				
				@Override
				public String nextElement() {
					return iterator.next();
				}
				
				@Override
				public boolean hasMoreElements() {
					return iterator.hasNext();
				}
			};
		}
		return kernel.getAttributeNames();
	}
	//#endregion

	//#region setAttribute(name,value)
	/**
	 * 覆盖方法
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void setAttribute(String name, Object value) {
		
		//#region 如果整个系统采用token模式
		if(baseFilter!=null && baseFilter.isTokenMode()) {

			// token 的 key
			String tokenVal = request.getHeader(baseFilter.getTokenKey());
			if(tokenVal==null || tokenVal.length()<1) {
				tokenVal = response.getHeader(baseFilter.getTokenKey());
				if(tokenVal==null || tokenVal.length()<1) {
					tokenVal = baseFilter.generateTokenId();
					response.setHeader(baseFilter.getTokenKey(),tokenVal);
				}
			}
			
			//baseFilter.getLog().log("---session setAttribute tokenVal:["+tokenVal+"] key:["+name+"] value:["+value+"]");
			
			// 拼装入参对象
			Map<String,Object> paraMap = new HashMap<>();
			paraMap.put("key",tokenVal);        // 设置获取内存值对应的对象（用户数据）
			paraMap.put("type","0");            // 0读取，1写入 2移除
			paraMap.put("time",baseFilter.getSessionTimeOut()); // 设置超时时间

			Map<String,Object> map = null; // 用户会话容器
			try {
				// 调用 内存数据容器 脚本，获取该token对应的用户容器
				map = (Map<String,Object>)baseFilter.getScriptLoader().invokeScript(this,"N100085",paraMap);
			}catch(Exception e) {
				e.printStackTrace();
			}
		
			if(map==null) {
				map = new HashMap<>();
				
				paraMap.put("type","1");            // 0读取，1写入 2移除
				paraMap.put("value",map);           // 需要写入的值
				paraMap.put("time",baseFilter.getSessionTimeOut()); // 设置超时时间
				
				try {
					// 执行存入内存
					baseFilter.getScriptLoader().invokeScript(this,"N100085",paraMap);
				}catch(Exception e) {
					e.printStackTrace();
				}
			}

			map.put(name,value);
			
			return;
		}
		//#endregion
		
		kernel.setAttribute(name,value);
	}
	//#endregion

	//#region removeAttribute(name)
	/**
	 * 覆盖方法
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void removeAttribute(String name) {
		
		//#region 如果整个系统采用token模式
		if(baseFilter!=null && baseFilter.isTokenMode()) {
			// token 的 key
			String tokenVal = request.getHeader(baseFilter.getTokenKey());
			if(tokenVal==null || tokenVal.length()<1) {
				tokenVal = response.getHeader(baseFilter.getTokenKey());
				if(tokenVal==null || tokenVal.length()<1) {
					return;
				}
			}
			
			baseFilter.getLog().log("---session removeAttribute tokenVal:["+tokenVal+"] key:["+name+"]");
			
			// 拼装入参对象
			Map<String,Object> paraMap = new HashMap<>();
			paraMap.put("key",tokenVal);        // 设置获取内存值对应的对象（用户数据）
			paraMap.put("type","0");            // 0读取，1写入 2移除
			paraMap.put("time",baseFilter.getSessionTimeOut()); // 设置超时时间

			Map<String,Object> map = null; // 用户会话容器
			try {
				// 调用 内存数据容器 脚本，获取该token对应的用户容器
				map = (Map<String,Object>)baseFilter.getScriptLoader().invokeScript(this,"N100085",paraMap);
			}catch(Exception e) {
				e.printStackTrace();
			}
			if(map==null) {
				return;
			}
			map.remove(name);
			return;
		}
		//#endregion
		
		kernel.removeAttribute(name);
	}
	//#endregion

	//#region invalidate()
	/**
	 * 覆盖方法
	 */
	@Override
	public void invalidate() {
		
		//#region 如果整个系统采用token模式
		if(baseFilter!=null && baseFilter.isTokenMode()) {

			// token 的 key
			String tokenVal = request.getHeader(baseFilter.getTokenKey());
			if(tokenVal==null || tokenVal.length()<1) {
				tokenVal = response.getHeader(baseFilter.getTokenKey());
				if(tokenVal==null || tokenVal.length()<1) {
					return;
				}
			}
			
			baseFilter.getLog().log("---session invalidate:["+tokenVal+"]");
			
			// 拼装入参对象
			Map<String,Object> paraMap = new HashMap<>();
			paraMap.put("key",tokenVal);        // 设置获取内存值对应的对象（用户数据）
			paraMap.put("type","2");            // 0读取，1写入 2移除

			// 调用 内存数据容器 脚本，获取该token对应的用户容器
			try {
				baseFilter.getScriptLoader().invokeScript(this,"N100085",paraMap);
			}catch(Exception e) {
				e.printStackTrace();
			}
			return;
		}
		//#endregion
		
		kernel.invalidate();
	}
	//#endregion

	//#region isNew()
	/**
	 * 覆盖方法
	 */
	@Override
	public boolean isNew() {
		return kernel.isNew();
	}
	//#endregion

	//#region getAttributeMap()
	/**
	 * 覆盖方法
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Map<String, Object> getAttributeMap() {
		
		//#region 如果整个系统采用token模式
		if(baseFilter!=null && baseFilter.isTokenMode()) {
			
			// token 的 key
			String tokenVal = request.getHeader(baseFilter.getTokenKey());
			if(tokenVal==null || tokenVal.length()<1) {
				tokenVal = response.getHeader(baseFilter.getTokenKey());
				if(tokenVal==null || tokenVal.length()<1) {
					return null;
				}
			}
			
			//baseFilter.getLog().log("---session getAttributeMap tokenVal:["+tokenVal+"]");
			
			// 拼装入参对象
			Map<String,Object> paraMap = new HashMap<>();
			paraMap.put("key",tokenVal);        // 设置获取内存值对应的对象（用户数据）
			paraMap.put("type","0");            // 0读取，1写入 2移除
			paraMap.put("time",baseFilter.getSessionTimeOut()); // 设置超时时间

			try {
				// 调用 内存数据容器 脚本，获取该token对应的用户容器
				return (Map<String,Object>)baseFilter.getScriptLoader().invokeScript(this,"N100085",paraMap);
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
		//#endregion

		// 构建返回值
		HashMap<String,Object> res = new HashMap<String,Object>();
		// 属性名枚举
		Enumeration<String> names = kernel.getAttributeNames();
		if(names!=null) {
			String name;
			Object value;
			while(names.hasMoreElements()) {
				name  = names.nextElement();
				value = kernel.getAttribute(name);
				if(value==null) {
					continue;
				}
				res.put(name,value);
			}
		}
		return res;
	}
	//#endregion
}







